package prac8;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

/**
 *
 * @author        Loke Kar Seng
 * @modified      Brendon Taylor (July 2009) - JavaDoc / Indentation / Style
 *                Brendon Taylor (Feb 2010) - JavaDoc
 *                Menghong Li (Sept 2011)
 *                Brendan Peterson
 * @since         March 2009?
 * @input         none
 * @output        {@link #menu()}
 * @errorHandling IOException: {@link #menu()}
 * @errorHandling IOException: {@link #readFromFile(String, BinarySearchListTree)}
 * @errorHandling FileNotFoundException: {@link #readFromFile(String, BinarySearchListTree)}
 * @knownBugs     none
 */
public class Anagram {
    
    /**
     * @complexity  O(U)*OCommand, where U is the number of times the user 
     *     chooses to enter a command (a large number) and OCommand is the 
     *     complexity of the best/worst command
     */
    public static void menu() {
        boolean quit = false;
        String command;
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        BinarySearchListTree<String, String> myTree = new BinarySearchListTree<String, String>();

        String menu[]={"Prac8 Anagram Tree Menu Options", 
                        "Read String",
                        "Read File",
                        "List",
                        "Search",
                        "Anagram",
                        "Quit"};
        try {
            while (!quit) { // command parsing loop
                // print menu
                for (int i = 0; i < menu.length; i++) {
                     System.out.println((i != 0 ? i + "." : " ") + menu[i]);
		}
                // read a command
                command = console.readLine();

                // process input command for menu
                if (command.equals("1")) { // Read String
                    // Read String
                    String str = null;
                    String sortedstr = null;
                    str = console.readLine();

                    if ((sortedstr=processInput(str)) != null) {
                        System.out.println("Inserting : " + str + " -> " + sortedstr);
                    } else {
                        System.out.println("Error: Input string.");
                    }
                } else if (command.equals("2")) { // Read File
                    String filename = null;
                    System.out.print("Filename: ");
                    filename = console.readLine();
                    readFromFile(filename, myTree);
                } else if (command.equals("3")) { // List
                	myTree.printInOrder();
                } else if (command.equals("4")) { // Search
                    String str = null;

                    str = console.readLine();
                    if (processInput(str) != null) {
                            System.out.println("Searching :" + str);
                            if(myTree.find(processInput(str), str)){
    							System.out.println("The word '" + str + "' was found in the anagram tree.");
    						} else {
    							System.out.println("The word '" + str + "' was not found in the anagram tree.");
    						}
                    } else {
                            System.out.println("Error: Input string.");
                    }
                } else if (command.equals("5")) { // Anagram
                	String str = null;
                    String sortedstr = null;
                    str = console.readLine();
                    
                    if ((sortedstr=processInput(str)) != null) {
                        System.out.println("Find anagram : " + str);
                        myTree.printAnagrams(sortedstr, str.toLowerCase());
                        System.out.println();
                    } else {
                        System.out.println("Error: Input string.");
                    }
				} else if (command.equals("6")) { // Quit
                    quit = true;
		} else {
                    System.out.println("Error: Unrecognized command number.");
		}
            }
        } catch (IOException e) {
            System.out.println("Error: Reading from console");
            System.exit(1);
        }
    }

    /**
     * Validates input - alphabetical characters.
     * 
     * @param       str String to validate
     * @return      lower-case sorted version of String
     * @see         #isAlpha(String)
     */
    private static String processInput(String str) {
	if (isAlpha(str)) { // or str.matches("[a-zA-Z]*")
            return lcSort(str);
	}
	return null;
    }
    
    /**
     * Checks that a string contains only alphabets. Case does not matter.
     * 
     * @return true if the string contains only alphabets 
     *     (specifically, if it belongs to the category "Lu", "Ll", "Lt", "Lm", 
     *     or "Lo" in the Unicode specification data file) otherwise false,
     *     the original string is not altered
     * @complexity  best and worse case: O(N) where N is the number of 
     *     characters in the string (assuming length(), charAt, and isLetter 
     *     are all O(1))
     */
    private static boolean isAlpha(String s) {
        for(int i = 0; i < s.length(); i++) {
            if (!Character.isLetter(s.charAt(i))) {
                return false;
	    }
        }
        
        return true;
    }
    
    /**
     * Sort a string in alphabetical order after being converted to lower case.
     * 
     * @pre         the string contains only ASCII alphabets
     * @return      a new lower case string sorted in alphabetical order
     * @complexity  O(N)+ OSort where N is the number of characters in the 
     *              string and OSort is the coplexity of sorting the array.
     */
    private static String lcSort(String s) {
        char [] c = s.toLowerCase().toCharArray();
        Arrays.sort(c);
        return new String(c);
    }
    
    /**
     * Reads a text file line by line into.
     * 
     * @param       fileName path to file
     * @param       myTree reference to our binary search tree to add the words to
     * @post        the list contains the text in the text file
     * @complexity  best and worse case: O(N*M) where N is the number of lines in the list and
     *              M is the complexity of reading a line from file
     */
    private static void readFromFile(String fileName, BinarySearchListTree<String, String> myTree) {
        BufferedReader inputReader;
        try {
            // have a go at opening the file
            inputReader = new BufferedReader(new FileReader(fileName));
        } catch (FileNotFoundException e) {
            System.out.println("File not found: " + fileName);
            return;
        }

        // the file is now open, lets read from it.
        String line;
        String sortedstr = null;
        try {
            while ((line = inputReader.readLine()) != null) {
                if((sortedstr = processInput(line)) != null){
                        System.out.println("Inserting : " + line + " -> " + sortedstr);
                        myTree.insert(sortedstr, line);
                } else{
                        System.out.println("Error: Input string from file " + fileName);
                }
            }
        } catch (IOException e) {
            // if we got here, then the readLine() died
            System.out.println("Error reading from file: " + fileName);
        }
    }
    
    /**
     * @param args command-line arguments
     */
    public static void main(String args[]) {
//        menu();

		BinarySearchListTree<String, String> BST = new BinarySearchListTree<String, String>();
		BST.insert("43", "1");
		BST.insert("31", "1");
		BST.insert("31", "1");
		BST.insert("20", "1");
		BST.insert("28", "1");
		BST.insert("40", "1");
		BST.insert("33", "1");
		BST.insert("64", "1");
		BST.insert("56", "1");
		BST.insert("47", "1");
		BST.insert("59", "1");
		BST.insert("89", "1");
		
		BST.testIterator();
    }
}